import 'package:bluetooth_protocols_plugin/library.dart';
import 'package:flutter/foundation.dart';

import '../tools/utils.dart';

// 解析加密
class EncryptDecryptHelper<T extends CryptoBase> {
  final T crypto;
  EncryptDecryptHelper(this.crypto);

  // 加密表的长度
  final int _cryptoTableLength = 256;

  // 是否显示日志信息
  void showLogger({bool show = true}) {
    crypto.needPrint = show;
  }

  // 加密 randCryptKey 随机索引
  Uint8List encrypt(Uint8List bytes, [int randCryptKey = -1]) {
    // 加解密过程相同
    if (crypto.needPrint == true) {
      debugPrint("加密前: $bytes");
    }
    _encrypt2decrypt(bytes, randCryptKey);
    if (crypto.escapeByte != null && crypto.needEscapeBytes != null) {
      if (crypto.needPrint == true) {
        debugPrint("加转义前: $bytes");
      }
      // 对需要转义的字节进行转义处理
      bytes = _segmentToEscape(
        bytes,
        crypto.escapeByte!,
        crypto.needEscapeBytes!,
        escaped: true,
      );
      if (crypto.needPrint == true) {
        debugPrint("加转义后: $bytes");
      }
    }
    if (crypto.needPrint == true) {
      debugPrint("加密后: $bytes");
    }
    return bytes;
  }

  // 解密 randCryptKey 随机索引
  Uint8List decrypt(Uint8List bytes, [int randCryptKey = -1]) {
    // 加解密过程相同
    if (crypto.needPrint == true) {
      debugPrint("解密前: $bytes");
    }
    _encrypt2decrypt(bytes, randCryptKey);
    if (crypto.escapeByte != null && crypto.needEscapeBytes != null) {
      if (crypto.needPrint == true) {
        debugPrint("去转义前: $bytes");
      }
      // 对需要转义的字节进行去转义处理
      bytes = _segmentToEscape(
        bytes,
        crypto.escapeByte!,
        crypto.needEscapeBytes!,
        escaped: false,
      );
      if (crypto.needPrint == true) {
        debugPrint("去转义后: $bytes");
      }
    }

    if (crypto.needPrint == true) {
      debugPrint("解密后: $bytes");
    }
    return bytes;
  }

  // 转义或去转义
  Uint8List _segmentToEscape(
    Uint8List bytes,
    int escapeByte,
    Uint8List needEscapeBytes, {
    required bool escaped,
  }) {
    Uint8List temp = bytes;
    final notEscapePrefixLength = crypto.notEscapePrefixLength ?? 0;
    Uint8List prefixBytes = bytes.sublist(0, notEscapePrefixLength);
    final notEscapeSuffixLength = crypto.notEscapeSuffixLength ?? 0;
    Uint8List suffixBytes =
        temp.sublist(temp.length - notEscapeSuffixLength, temp.length);
    final segmentToEscape = bytes.sublist(
        notEscapePrefixLength, temp.length - notEscapeSuffixLength);
    if (escaped) {
      Uint8List newBytes = Uint8List.fromList(Utils.insertBeforTargets(
        segmentToEscape,
        targets: needEscapeBytes,
        insert: escapeByte,
      ));
      return Uint8List.fromList([...prefixBytes, ...newBytes, ...suffixBytes]);
    } else {
      Uint8List newBytes = Uint8List.fromList(Utils.removeInsertedBytes(
        segmentToEscape,
        insert: escapeByte,
      ));
      return Uint8List.fromList([...prefixBytes, ...newBytes, ...suffixBytes]);
    }
  }

  // 加密 randCryptKey 随机索引
  void _encrypt2decrypt(Uint8List bytes, [int randCryptKey = -1]) {
    bool shouldEncrypt = _needEncrypt();
    if (crypto.needPrint == true) {
      debugPrint("是否加密：$shouldEncrypt");
    }
    // 是否需要加密
    if (!shouldEncrypt) return;
    // 随机码
    if (crypto.randCryptKeyIndex != null) {
      if (crypto.randCryptKeyIndex! >= 0 &&
          crypto.randCryptKeyIndex! < bytes.length) {
        randCryptKey = bytes[crypto.randCryptKeyIndex!];
      } else {
        throw RangeError('randCryptKeyIndex is out of bounds');
      }
    }
    // 加解密
    if (crypto.notCryptoPrefixLength != null &&
        crypto.notCryptoSuffixLength != null &&
        crypto.randCryptKeyIndex != null &&
        crypto.cryptoTable != null) {
      int tempRandCryptKey = randCryptKey;
      for (int i = crypto.notCryptoPrefixLength!;
          i < bytes.length - crypto.notCryptoSuffixLength!;
          i++) {
        // 掐头去尾，加密中间段
        tempRandCryptKey %= _cryptoTableLength;
        bytes[i] = bytes[i] ^ crypto.cryptoTable![tempRandCryptKey++];
      }
    }
  }

  // 是否需要加密
  bool _needEncrypt() {
    return crypto.needCrypto &&
        (crypto.cryptoTable?.length ?? 0) == _cryptoTableLength &&
        crypto.cryptoTable != null &&
        crypto.randCryptKeyIndex != null;
  }
}
